/****************************************************************************
 *
 * Copyright (C) 2003-2010 Los Alamos National Security, LLC
 *                         Packet Analytics Corporation
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License Version 2 as
 * published by the Free Software Foundation.  You may not use, modify or
 * distribute this program under any other version of the GNU General
 * Public License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 ****************************************************************************/
package nfse;

import java.io.File;
import java.io.FileFilter;
import java.io.FilenameFilter;
import java.io.PrintWriter;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.HashSet;

public class BackupPostgreSQL {

    public static String BACKUP_DIR = null;

    /**
     * Intended to be run nightly as a cron job. Must be run by a user that has
     * been granted access to the PostgreSQL databases.
     * 
     * @param args
     */
    public static void main(String[] args) {
        BackupPostgreSQL backup = new BackupPostgreSQL();
        if (args.length >0) {
            File backupDir = new File(args[0]);
            if (!backupDir.exists())
                backupDir.mkdirs();
            BACKUP_DIR = backupDir.getAbsolutePath();
        }
        backup.process();
    }

    public void process() {

        MetaDatabase mdb = null;
        try {

            NetFSE.configure();

            if (BACKUP_DIR == null)
                BACKUP_DIR = NetFSE.TEMP_DIR;

            File tempScript = new File(BACKUP_DIR + "/backup_n" + NetFSE.NODE_ID + "_" + System.currentTimeMillis()
                    + ".sh");
            PrintWriter tempOut = new PrintWriter(tempScript);

            File backupDir = new File(BACKUP_DIR);
            if (!backupDir.exists())
                backupDir.mkdirs();

            if (!backupDir.exists() || !backupDir.isDirectory()) {
                throw new Exception("BACKUP: The backup directory specified does not exist or is not a directory: "
                        + BACKUP_DIR);
            }

            ArrayList<Integer> sensors = new ArrayList<Integer>();
            ArrayList<Integer> tools = new ArrayList<Integer>();
            mdb = MetaDatabase.create();
            Statement s = mdb.createStatement();
            ResultSet rs = s.executeQuery("select * from sensors");
            while (rs.next()) {
                int sensorID = rs.getInt("id");
                int toolID = rs.getInt("tool_id");
                String name = rs.getString("name");
                sensors.add(sensorID);
                tools.add(toolID);
            }
            rs.close();

            for (int sensorID : sensors) {
                SensorInfo sensorInfo = NetFSE.getSensorInfo(sensorID);
                ToolInfo tool = NetFSE.getToolInfo(sensorInfo.getToolID());
                String[] existingBackups = backupDir.list(new SensorFileFilter(sensorID, NetFSE.NODE_ID));
                HashSet<String> existingBackupSet = new HashSet<String>();
                for (String existing : existingBackups)
                    existingBackupSet.add(existing);

                String sql = "select * from temp_tables where node_id=" + NetFSE.NODE_ID + " and sensor_id=" + sensorID;
                rs = s.executeQuery(sql);
                while (rs.next()) {
                    String tableName = rs.getString("table_name");
                    String backupName = tableName + ".sql";
                    String backupNameGZ = tableName + ".sql.gz";
                    boolean backup = false;
                    if (existingBackupSet.contains(backupName) || existingBackupSet.contains(backupNameGZ)) {
                        // Check to see of this is the latest database (min_ts
                        // is null)
                        Timestamp ts = rs.getTimestamp("min_ts");
                        if (ts == null)
                            backup = true;
                        else
                            backup = false;
                        // ignore, already backed up
                    } else {
                        backup = true;
                    }

                    if (backup) {
                        // back it up
                        // ...

                        System.out.println("Backing up " + tableName);
                        String outfileName = tableName + ".sql";
                        File outfile = new File(BACKUP_DIR + "/" + outfileName);
                        String pgDump = NetFSE.PG_DUMP + " " + tool.getName().toLowerCase() + " -t " + tableName
                                + " > " + outfile.getAbsolutePath();
                        tempOut.println(pgDump);

                        String gzip = "gzip " + outfile.getAbsolutePath();
                        tempOut.println(gzip);
                    }

                    // Remove this entry
                    existingBackupSet.remove(backupName);
                    existingBackupSet.remove(backupNameGZ);
                }
                rs.close();

                /**
                 * Anything still in the entry set is no longer in temp_tables
                 * and has been migrated. Delete old backups.
                 */
                for (String existing : existingBackupSet) {
                    File tempFile = new File(existing);
                    tempFile.delete();
                }
            }

            // TODO create dump of metadatabase - must be unique based on
            // nodeID, timestamp
            String metadataFileName = "metadata_n" + NetFSE.NODE_ID + ".sql";

            File outfile = new File(BACKUP_DIR + "/" + metadataFileName);
            String pgDump = NetFSE.PG_DUMP + " metadata > " + outfile.getAbsolutePath();
            tempOut.println(pgDump);

            String gzip = "gzip " + outfile.getAbsolutePath();
            tempOut.println(gzip);

            tempOut.flush();
            tempOut.close();

            NetFSEUtil.execAndWait("sh " + tempScript.getAbsolutePath());
            
            //tempScript.delete();

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                mdb.closeConnection();
            } catch (Exception e) {

            }
        }

    }

    private class SensorFileFilter implements FilenameFilter {

        private int sensorID = -1;

        private int nodeID = -1;

        private String prefix = null;

        public SensorFileFilter(int sensor, int node) {
            this.sensorID = sensor;
            this.nodeID = node;
            this.prefix = "s" + sensorID + "_n" + nodeID + "_";
        }

        public boolean accept(File dir, String name) {
            if (name.startsWith(prefix))
                return true;
            return false;
        }

    }

}
